package pac

import (
	"fmt"
	"math"
	"slgw_web/serial/dto"
	"slgw_web/serial/util"
	"strconv"
	"strings"
	"time"

	"github.com/robinson/gos7"
	models "openzbox.com/frame/echo/models/sl_gw01"
)

// func init() {
// 	//SiemensClient()
// }

// 重新连接
func SiemensRestart(id int64) {
	for i, _ := range Test {
		if Test[i].DataID == id {
			Test[i].S7Handler.Close()
			handler := Test[i].S7Handler
			//重连
			err := handler.Connect()
			if err != nil {
				util.Error("西门子S7协议重启连接失败" + err.Error())
				continue
			}
			client := gos7.NewClient(handler)
			newData := dto.CollectSet{
				S7Client:   client,
				S7Handler:  handler,
				DataID:     Test[i].DataID,
				ComName:    Test[i].ComName,
				TPITV:      Test[i].TPITV,
				IsEnd:      true,
				Timeout:    Test[i].Timeout,
				RetryCount: Test[i].RetryCount,
			}
			util.Error("PortName:" + Test[i].ComName + ",西门子S7重启成功")
			// 找到匹配的数据，将其替换为新的数据
			Test[i] = newData

			break // 找到后退出循环
		}
	}
}

// 连接初始化
func SiemensClient() {
	for _, data := range util.Serial {
		agreement, err := strconv.Atoi(data.Agreement)
		if err != nil {
			util.Error(data.ComName + "协议转换失败")
			return
		}
		if agreement == int(dto.SiemensS7TCP) { //SiemensS7TCP模式
			if data.Rack == nil {
				util.Error(data.ComName + "协议Rack不可为空")
				return
			}
			if data.Slot == nil {
				util.Error(data.ComName + "协议Slot不可为空")
				return
			}
			//PLC tcp连接客户端
			handler := gos7.NewTCPClientHandler(data.ComName, *data.Rack, *data.Slot)
			//连接及读取超时
			handler.Timeout = time.Duration(data.Timeout) * time.Second
			//关闭连接超时
			handler.IdleTimeout = 2000 * time.Second
			//打开连接
			err := handler.Connect()
			if err != nil {
				util.Error("西门子S7协议 " + data.ComName + " 连接失败,重连中,err:" + err.Error())
				for {
					err = handler.Connect()
					if err != nil {
						time.Sleep(1 * time.Second)
						util.Error("西门子S7协议 " + data.ComName + " 重连失败，等待再次重连,err:" + err.Error())
					} else {
						util.Error("西门子S7协议 " + data.ComName + " 重连成功")
						break
					}

				}
				//continue
			}
			//函数退出时关闭连接
			//defer handler.Close()

			//获取PLC对象
			client := gos7.NewClient(handler)
			if data.TPITV == "" || data.TPITV == "0" {
				data.TPITV = "60"

			}
			tpitv, err := strconv.Atoi(data.TPITV)
			if err != nil {
				util.Error(data.ComName + "的采集周期时间配置错误,将默认为60秒")
				tpitv = 60
			}
			test1 := dto.CollectSet{
				S7Client:   client,
				S7Handler:  handler,
				DataID:     data.ID,
				ComName:    data.ComName,
				TPITV:      tpitv,
				IsEnd:      true,
				Timeout:    int(data.Timeout),
				RetryCount: data.RetryCount,
			}
			Test = append(Test, test1)
		}
	}
}
func Siemenss7(t dto.CollectSet) {
	go func() {
		ti := 0
		for i := range Test {
			if t.DataID == Test[i].DataID {
				ti = i
				t = Test[i]
				//Test[i].IsEnd = false
				break
			}
		}
		if Test[ti].IsEnd {
			Test[ti].IsEnd = false
			DataID := t.DataID
			S7Client := Test[ti].S7Client
			for j := range util.Serial_Slave {

				data2 := util.Serial_Slave[j]
				if data2.IsCollect == 1 {
					if data2.Serial_ID == DataID {
						for _, item := range util.Serial_Slave_Detail {
							if item.Serial_ID == DataID && item.Serial_Slave_ID == data2.ID {
								time.Sleep(200 * time.Millisecond)
								if item.ValueType == nil {
									util.Error(t.ComName + ",id:" + strconv.Itoa(int(item.ID)) + "的数据类型未选择，无法采集数据")
									continue
								}
								if item.SiemensType == nil {
									util.Error(t.ComName + ",id:" + strconv.Itoa(int(item.ID)) + "的通道类型未选择，无法采集数据")
									continue
								}
								hexString := ""
								value2 := ""
								value3 := ""
								//fmt.Println("*item.ValueType", *item.ValueType)
								switch *item.ValueType {
								case int(dto.Bool):
									var value bool
									hexString, value2, value3 = AGRead(S7Client, *item.SiemensType, value, item.SiemensAdress, DataID)
								case int(dto.UByte):
									var value uint8
									hexString, value2, value3 = AGRead(S7Client, *item.SiemensType, value, item.SiemensAdress, DataID)
								case int(dto.Short):
									var value int16
									hexString, value2, value3 = AGRead(S7Client, *item.SiemensType, value, item.SiemensAdress, DataID)
								case int(dto.UShort):
									var value uint16
									hexString, value2, value3 = AGRead(S7Client, *item.SiemensType, value, item.SiemensAdress, DataID)
								case int(dto.Int32):
									var value int32
									hexString, value2, value3 = AGRead(S7Client, *item.SiemensType, value, item.SiemensAdress, DataID)
								case int(dto.UInt32):
									var value uint32
									hexString, value2, value3 = AGRead(S7Client, *item.SiemensType, value, item.SiemensAdress, DataID)
								case int(dto.Long):
									var value int64
									hexString, value2, value3 = AGRead(S7Client, *item.SiemensType, value, item.SiemensAdress, DataID)
								case int(dto.ULong):
									var value uint64
									hexString, value2, value3 = AGRead(S7Client, *item.SiemensType, value, item.SiemensAdress, DataID)
								case int(dto.Float32):
									var value float32
									hexString, value2, value3 = AGRead(S7Client, *item.SiemensType, value, item.SiemensAdress, DataID)
								case int(dto.Double):
									var value float64
									hexString, value2, value3 = AGRead(S7Client, *item.SiemensType, value, item.SiemensAdress, DataID)

								}
								AddDataSiemens(item, hexString, value2, value3)
							}
						}

					}
				} else {
					logStr := "Name:" + data2.Name + ",已配置不进行采集"
					util.IsCollectLog(logStr)
				}
			}
			Test[ti].IsEnd = true
			// for i := range Test {
			// 	if t.DataID == Test[i].DataID {
			// 		Test[i].IsEnd = true
			// 		break
			// 	}
			// }
		} else {
			return
		}

	}()
}

func AGRead(S7Client gos7.Client, SiemensType int, value interface{}, SiemensAdress string, dataID int64) (string, string, string) {

	buffer := make([]byte, 8)
	//fmt.Println("SiemensType", SiemensType)
	switch SiemensType {
	case int(dto.I):
		siemensAdress, err := strconv.Atoi(SiemensAdress)
		if err != nil {
			util.Error("西门子协议地址转换失败")
			return "", "", ""
		}
		err = S7Client.AGReadEB(siemensAdress, 8, buffer)
		if err != nil {
			util.Error("西门子协议读取错误，正在重连,err:" + err.Error())
			SiemensRestart(dataID)
		}
	case int(dto.Q):
		siemensAdress, err := strconv.Atoi(SiemensAdress)
		if err != nil {
			util.Error("西门子协议地址转换失败")
			return "", "", ""
		}
		err = S7Client.AGReadAB(siemensAdress, 8, buffer)
		if err != nil {
			util.Error("西门子协议读取错误，正在重连,err:" + err.Error())
			SiemensRestart(dataID)
		}
	case int(dto.M):
		siemensAdress, err := strconv.Atoi(SiemensAdress)
		if err != nil {
			util.Error("西门子协议地址转换失败")
			return "", "", ""
		}
		err = S7Client.AGReadMB(siemensAdress, 8, buffer)
		if err != nil {
			util.Error("西门子协议读取错误，正在重连,err:" + err.Error())
			SiemensRestart(dataID)
		}
	case int(dto.DB):
		if strings.Contains(SiemensAdress, ".") {
			siemensAdress := strings.Split(SiemensAdress, ".")
			address, err := strconv.Atoi(siemensAdress[0])
			if err != nil {
				util.Error("DB通道的西门子协议地址转换失败，必须包含小数点")
				return "", "", ""
			}
			start, err := strconv.Atoi(siemensAdress[1])
			if err != nil {
				util.Error("DB通道的西门子协议地址转换失败，必须包含小数点")
				return "", "", ""
			}
			err = S7Client.AGReadDB(address, start, 8, buffer) //DB
			if err != nil {
				util.Error("西门子协议读取错误，正在重连,err:" + err.Error())
				SiemensRestart(dataID)
			}
		} else {
			util.Error("西门子协议DB的地址位填写错误，格式应该类似DB100.1")
			return "", "", ""
		}
	}
	//fmt.Println("buffer", buffer)
	hexString, vString, value3 := Gethexvstring(value, buffer)
	// hexString := ""
	// vString := ""

	//fmt.Println("hexString", hexString)
	//fmt.Println("vString", vString)
	return hexString, vString, value3
}

// 高低位转换
func ConvertEndian(byteBuffer []byte) []byte {
	result := append(byteBuffer[2:], byteBuffer[:2]...)
	return result
}
func Gethexvstring(value interface{}, buffer []byte) (string, string, string) {
	var helper gos7.Helper
	hexString := ""
	vString := ""
	switch v := value.(type) {
	case bool: //1位 true or false c#接收 Convert.ToInt16(E1,16)
		helper.GetValueAt(buffer, 0, &v)
		if v {
			hexString = "0001"
		} else {
			hexString = "0000"
		}
		vString = hexString
	case uint8: //1字节 c#接收 Convert.ToInt16(E1,16)
		helper.GetValueAt(buffer, 0, &v)
		hexString = fmt.Sprintf("%04X", v)
		vString = fmt.Sprint(v)
	case int16: //2字节 c#接收 Convert.ToInt16("cfc7",16)
		helper.GetValueAt(buffer, 0, &v)
		hexString = int16ToHex(v)
		vString = fmt.Sprint(v)
	case uint16: //2字节 c#接收 Convert.ToUInt16(E1,16)
		helper.GetValueAt(buffer, 0, &v)
		hexString = fmt.Sprintf("%04X", v)
		vString = fmt.Sprint(v)
	case int32: //4字节 c#接收 Convert.ToInt32(E1+E2,16)
		helper.GetValueAt(buffer, 0, &v)
		hexString = int32ToHex(v)
		vString = fmt.Sprint(v)
	case uint32: //4字节 c#接收 Convert.ToUInt32(E1+E2,16)
		helper.GetValueAt(buffer, 0, &v)
		hexString = fmt.Sprintf("%08X", v)
		vString = fmt.Sprint(v)
	case int64: //8字节 c#接收 Convert.ToInt64(E1+E2+E3,16)
		helper.GetValueAt(buffer, 0, &v)
		hexString = int64ToHex(v)
		vString = fmt.Sprint(v)
	case uint64: //8字节 c#接收 Convert.ToUInt64(E1+E2+E3+E4,16)
		helper.GetValueAt(buffer, 0, &v)
		hexString = fmt.Sprintf("%016X", v)
		vString = fmt.Sprint(v)
	case float32: // c#接收BitConverter.ToSingle(BitConverter.GetBytes(Convert.ToUInt32(E1+E2,16)), 0)
		helper.GetValueAt(buffer, 0, &v)
		f := float32(v)
		hexString = float32ToHex(f)
		normalNumber := strconv.FormatFloat(float64(f), 'f', -1, 32)
		vString = normalNumber //fmt.Sprint(v)
	case float64: //c#接收 BitConverter.ToDouble(BitConverter.GetBytes(Convert.ToUInt64(E1+E2+E3+E4,16)), 0)
		helper.GetValueAt(buffer, 0, &v)
		f := float64(v)
		hexString = float64ToHex(f)
		normalNumber := strconv.FormatFloat(f, 'f', -1, 64)
		vString = normalNumber // fmt.Sprint(v)
	}
	//value3 := fmt.Sprintf("%v", buffer)
	//value3 := hex.EncodeToString(buffer)
	return hexString, vString, hexString
}

// 格式转换
func float64ToHex(f float64) string {
	bits := math.Float64bits(f)
	hexString := strconv.FormatUint(uint64(bits), 16)
	return hexString
}
func float32ToHex(f float32) string {
	bits := math.Float32bits(f)
	hexString := strconv.FormatUint(uint64(bits), 16)
	return hexString
}
func int16ToHex(number int16) string {
	// 将 int16 转换为 uint16，因为 fmt.Sprintf 不接受有符号整数
	unsignedNumber := uint16(number)
	hexString := fmt.Sprintf("%04x", unsignedNumber)
	return hexString
}
func int32ToHex(number int32) string {
	unsignedNumber := uint32(number)
	hexString := fmt.Sprintf("%08x", unsignedNumber)
	return hexString
}
func int64ToHex(number int64) string {
	unsignedNumber := uint64(number)
	hexString := fmt.Sprintf("%16x", unsignedNumber)
	return hexString
}

func AddDataSiemens(data models.Serial_Slave_Detail, collectData string, value2 string, value3 string) {

	test1 := dto.Serial_Slave_Detail_Cache{
		ID:               data.ID,
		Serial_ID:        data.Serial_ID,
		Serial_Slave_ID:  data.Serial_Slave_ID,
		CollectAddressID: *data.CollectAddressID,
		Type:             data.Type,
		Value:            collectData,
		CreateTime:       time.Now().Format("2006-01-02 15:04:05"),
		Value2:           &value2,
		Value3:           &value3,
		ValueError:       &collectData,
	}
	// 在 append 之前，遍历 collectDataListNew，根据 ID 判断是否需要覆盖
	updated := false
	for i, data := range util.CollectDataList {
		if data.ID == test1.ID {
			// 找到相同 ID 的元素，进行覆盖
			util.CollectDataList[i] = test1
			updated = true
			break
		}
	}
	// 如果没有找到相同 ID 的元素，进行追加
	if !updated {
		util.CollectDataList = append(util.CollectDataList, test1)
	}

}
